package com.example.monitoring.service;

import com.example.monitoring.config.MonitoringProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 配置文件管理服务
 * 支持从外部文件和classpath加载配置
 * 优先级：外部文件 > classpath资源
 * 
 * @author rsz
 * @since 2024-04-14
 */
@Slf4j
@Service
public class ConfigurationFileService {

    private final ObjectMapper objectMapper;
    private final ResourceLoader resourceLoader;
    
    @Value("${monitoring.config.file-path:./config/monitoring-config.json}")
    private String configFilePath;
    
    public ConfigurationFileService(ObjectMapper objectMapper, ResourceLoader resourceLoader) {
        this.objectMapper = objectMapper;
        this.resourceLoader = resourceLoader;
        // 美化输出的JSON文件
        this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
    }
    
    @PostConstruct
    public void init() {
        // 确保配置目录存在
        try {
            Path configDir = Paths.get(configFilePath).getParent();
            if (configDir != null && !Files.exists(configDir)) {
                Files.createDirectories(configDir);
                log.info("已创建配置目录: {}", configDir);
            }
        } catch (IOException e) {
            log.error("创建配置目录失败", e);
        }
    }
    
    /**
     * 保存配置到文件
     * 注意：只能保存到外部文件，无法保存到JAR包内
     * 
     * @param properties 监控配置
     * @return 是否保存成功
     */
    public boolean saveConfiguration(MonitoringProperties properties) {
        try {
            objectMapper.writeValue(new File(configFilePath), properties);
            log.info("已保存配置到文件: {}", configFilePath);
            return true;
        } catch (IOException e) {
            log.error("保存配置到文件失败: {}", configFilePath, e);
            return false;
        }
    }
    
    /**
     * 从文件加载配置
     * 优先从外部文件加载，如果不存在则从classpath加载
     * 
     * @return 监控配置，如果加载失败返回null
     */
    public MonitoringProperties loadConfiguration() {
        // 1. 优先尝试从外部文件加载
        File configFile = new File(configFilePath);
        if (configFile.exists()) {
            try {
                MonitoringProperties properties = objectMapper.readValue(configFile, MonitoringProperties.class);
                log.info("已从外部文件加载配置: {}", configFilePath);
                return properties;
            } catch (IOException e) {
                log.error("从外部文件加载配置失败: {}", configFilePath, e);
                // 继续尝试从classpath加载
            }
        } else {
            log.info("外部配置文件不存在: {}, 尝试从classpath加载", configFilePath);
        }
        
        // 2. 从classpath加载配置文件
        return loadFromClasspath();
    }
    
    /**
     * 从classpath加载配置文件
     * 
     * @return 监控配置，如果加载失败返回null
     */
    private MonitoringProperties loadFromClasspath() {
        try {
            // 尝试从classpath加载配置文件
            String classpathLocation = "config/monitoring-config.json";
            Resource resource = new ClassPathResource(classpathLocation);
            
            if (resource.exists()) {
                try (InputStream inputStream = resource.getInputStream()) {
                    MonitoringProperties properties = objectMapper.readValue(inputStream, MonitoringProperties.class);
                    log.info("已从classpath加载配置: {}", classpathLocation);
                    return properties;
                }
            } else {
                log.warn("classpath中也未找到配置文件: {}", classpathLocation);
            }
        } catch (IOException e) {
            log.error("从classpath加载配置失败", e);
        }
        
        log.error("无法从任何位置加载配置文件，请检查配置文件是否存在");
        return null;
    }
    
    /**
     * 检查配置文件是否存在（外部文件或classpath）
     * 
     * @return 是否存在可用的配置文件
     */
    public boolean configExists() {
        // 检查外部文件
        File configFile = new File(configFilePath);
        if (configFile.exists()) {
            return true;
        }
        
        // 检查classpath资源
        Resource resource = new ClassPathResource("config/monitoring-config.json");
        return resource.exists();
    }
    
    /**
     * 获取配置文件路径
     * 
     * @return 配置文件路径
     */
    public String getConfigFilePath() {
        return configFilePath;
    }
} 